﻿import pygame
import sys
import math
import random
from pygame.locals import *

# 初始化 Pygame
pygame.init()

# 屏幕设置
WIDTH, HEIGHT = 1000, 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("高斯著名公式动画演示")

# 颜色定义
BACKGROUND = (25, 30, 40)
TEXT_COLOR = (220, 220, 220)
HIGHLIGHT = (255, 215, 0)
FORMULA_COLOR = (100, 200, 255)
GRID_COLOR = (60, 70, 90)
NUMBER_COLOR = (180, 180, 220)
SUM_COLOR = (0, 200, 150)
ERROR_COLOR = (255, 100, 100)

# 字体
title_font = pygame.font.SysFont("simhei", 48, bold=True)
subtitle_font = pygame.font.SysFont("simhei", 32)
text_font = pygame.font.SysFont("simhei", 24)
number_font = pygame.font.SysFont("Arial", 20, bold=True)
formula_font = pygame.font.SysFont("Arial", 36, bold=True)

# 时钟
clock = pygame.time.Clock()
FPS = 60

# 高斯公式计算
def gauss_sum(n):
    return n * (n + 1) // 2

# 数字类
class Number:
    def __init__(self, value, x, y):
        self.value = value
        self.x = x
        self.y = y
        self.target_x = x
        self.target_y = y
        self.size = 30
        self.color = NUMBER_COLOR
        self.highlight = False
        self.paired = False
        self.pair_value = None
        self.animation_progress = 0
        self.visible = True
    
    def draw(self, surface):
        if not self.visible:
            return
            
        # 绘制数字背景
        color = HIGHLIGHT if self.highlight else self.color
        pygame.draw.circle(surface, color, (int(self.x), int(self.y)), self.size)
        pygame.draw.circle(surface, (40, 45, 60), (int(self.x), int(self.y)), self.size, 2)
        
        # 绘制数字
        text = number_font.render(str(self.value), True, (20, 20, 30))
        text_rect = text.get_rect(center=(int(self.x), int(self.y)))
        surface.blit(text, text_rect)
        
        # 绘制配对线
        if self.paired and self.pair_value:
            pygame.draw.line(surface, HIGHLIGHT, (self.x, self.y), 
                            (self.pair_value.x, self.pair_value.y), 2)
            
            # 绘制和
            mid_x = (self.x + self.pair_value.x) // 2
            mid_y = (self.y + self.pair_value.y) // 2
            sum_text = number_font.render(f"{self.value + self.pair_value.value}", True, SUM_COLOR)
            sum_rect = sum_text.get_rect(center=(mid_x, mid_y))
            pygame.draw.rect(surface, (30, 35, 45), 
                           (mid_x - 20, mid_y - 15, 40, 30), border_radius=5)
            surface.blit(sum_text, sum_rect)
    
    def update(self):
        # 平滑移动动画
        if abs(self.x - self.target_x) > 1:
            self.x += (self.target_x - self.x) * 0.1
        else:
            self.x = self.target_x
            
        if abs(self.y - self.target_y) > 1:
            self.y += (self.target_y - self.y) * 0.1
        else:
            self.y = self.target_y

# 高斯公式演示类
class GaussDemo:
    def __init__(self):
        self.numbers = []
        self.stage = 0  # 0: 初始, 1: 配对, 2: 公式, 3: 计算
        self.stage_progress = 0
        self.max_stage = 3
        self.n = 100
        self.pairs = []
        self.sum = 0
        self.formula_visible = False
        self.calculation_visible = False
        self.error_visible = False
        self.create_numbers()
        
    def create_numbers(self):
        # 创建1到100的数字
        self.numbers = []
        grid_size = 40
        start_x = 100
        start_y = 200
        
        # 创建网格布局的数字
        for i in range(1, self.n + 1):
            row = (i - 1) // 10
            col = (i - 1) % 10
            x = start_x + col * grid_size
            y = start_y + row * grid_size
            self.numbers.append(Number(i, x, y))
    
    def next_stage(self):
        if self.stage < self.max_stage:
            self.stage += 1
            self.stage_progress = 0
            self.prepare_stage()
    
    def prepare_stage(self):
        if self.stage == 1:  # 配对阶段
            # 创建配对 (1和100, 2和99, 等等)
            self.pairs = []
            for i in range(self.n // 2):
                num1 = self.numbers[i]
                num2 = self.numbers[self.n - 1 - i]
                self.pairs.append((num1, num2))
                
                # 设置目标位置
                num1.target_x = WIDTH // 2 - 150
                num1.target_y = 300 - i * 30
                num2.target_x = WIDTH // 2 + 150
                num2.target_y = 300 - i * 30
                
                # 标记为已配对
                num1.paired = True
                num2.paired = True
                num1.pair_value = num2
                num2.pair_value = num1
                
            # 如果有奇数个数字，中间的数字单独处理
            if self.n % 2 == 1:
                mid_num = self.numbers[self.n // 2]
                mid_num.target_x = WIDTH // 2
                mid_num.target_y = 300 - (self.n // 2) * 15
                mid_num.highlight = True
        
        elif self.stage == 2:  # 公式阶段
            self.formula_visible = True
            
        elif self.stage == 3:  # 计算阶段
            self.calculation_visible = True
            self.sum = gauss_sum(self.n)
    
    def update(self):
        # 更新所有数字
        for number in self.numbers:
            number.update()
        
        # 更新阶段进度
        if self.stage == 1:
            self.stage_progress += 0.01
            if self.stage_progress > 1:
                self.stage_progress = 1
        
        elif self.stage == 2:
            self.stage_progress += 0.01
            if self.stage_progress > 1:
                self.stage_progress = 1
        
        elif self.stage == 3:
            self.stage_progress += 0.01
            if self.stage_progress > 1:
                self.stage_progress = 1
    
    def draw(self, surface):
        # 绘制标题
        title = title_font.render("高斯著名公式动画演示", True, TEXT_COLOR)
        surface.blit(title, (WIDTH // 2 - title.get_width() // 2, 30))
        
        # 绘制故事背景
        story = "高斯在小学时，老师布置了一个任务：计算1+2+3+...+100的和"
        story_text = text_font.render(story, True, TEXT_COLOR)
        surface.blit(story_text, (WIDTH // 2 - story_text.get_width() // 2, 100))
        
        # 绘制数字网格
        if self.stage == 0 or self.stage == 1:
            for i in range(11):
                pygame.draw.line(surface, GRID_COLOR, 
                                (100, 200 + i * 40), 
                                (100 + 9 * 40, 200 + i * 40), 1)
                pygame.draw.line(surface, GRID_COLOR, 
                                (100 + i * 40, 200), 
                                (100 + i * 40, 200 + 10 * 40), 1)
        
        # 绘制所有数字
        for number in self.numbers:
            number.draw(surface)
        
        # 绘制公式
        if self.formula_visible:
            formula_y = 500
            
            # 公式标题
            formula_title = subtitle_font.render("高斯发现的公式:", True, FORMULA_COLOR)
            surface.blit(formula_title, (WIDTH // 2 - formula_title.get_width() // 2, formula_y))
            
            # 公式
            formula = formula_font.render(f"1 + 2 + 3 + ... + n = n(n+1)/2", True, FORMULA_COLOR)
            surface.blit(formula, (WIDTH // 2 - formula.get_width() // 2, formula_y + 50))
            
            # 解释
            explanation = text_font.render("将数字配对：首尾相加，每对的和都是n+1，共有n/2对", True, TEXT_COLOR)
            surface.blit(explanation, (WIDTH // 2 - explanation.get_width() // 2, formula_y + 100))
        
        # 绘制计算结果
        if self.calculation_visible:
            calc_y = 500 if not self.formula_visible else 600
            
            # 计算过程
            calc_text = formula_font.render(f"1 + 2 + 3 + ... + 100 = 100 × 101 / 2 = 5050", True, SUM_COLOR)
            surface.blit(calc_text, (WIDTH // 2 - calc_text.get_width() // 2, calc_y))
            
            # 实际值
            actual_text = text_font.render(f"实际值: {self.sum}", True, SUM_COLOR)
            surface.blit(actual_text, (WIDTH // 2 - actual_text.get_width() // 2, calc_y + 50))
        
        # 绘制错误信息
        if self.error_visible:
            error_text = text_font.render("请输入1到200之间的整数", True, ERROR_COLOR)
            surface.blit(error_text, (WIDTH // 2 - error_text.get_width() // 2, HEIGHT - 100))
        
        # 绘制控制说明
        controls = [
            "空格键: 下一步演示",
            "R键: 重置演示",
            "数字键: 输入n值 (1-200)",
            "回车键: 应用新的n值"
        ]
        
        for i, text in enumerate(controls):
            control_text = text_font.render(text, True, TEXT_COLOR)
            surface.blit(control_text, (20, HEIGHT - 150 + i * 30))
        
        # 绘制当前n值
        n_text = text_font.render(f"当前n值: {self.n}", True, TEXT_COLOR)
        surface.blit(n_text, (WIDTH - n_text.get_width() - 20, HEIGHT - 50))

# 主函数
def main():
    demo = GaussDemo()
    input_mode = False
    input_text = ""
    
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == QUIT:
                running = False
            
            elif event.type == KEYDOWN:
                if event.key == K_SPACE:
                    demo.next_stage()
                
                elif event.key == K_r:
                    demo = GaussDemo()
                    input_mode = False
                    input_text = ""
                
                elif event.key == K_n:
                    input_mode = True
                    input_text = ""
                
                elif event.key == K_RETURN and input_mode:
                    try:
                        n = int(input_text)
                        if 1 <= n <= 200:
                            demo.n = n
                            demo.create_numbers()
                            demo.stage = 0
                            demo.stage_progress = 0
                            demo.formula_visible = False
                            demo.calculation_visible = False
                            demo.error_visible = False
                        else:
                            demo.error_visible = True
                    except ValueError:
                        demo.error_visible = True
                    input_mode = False
                    input_text = ""
                
                elif event.key == K_ESCAPE:
                    input_mode = False
                    input_text = ""
                    demo.error_visible = False
                
                elif input_mode and event.key == K_BACKSPACE:
                    input_text = input_text[:-1]
                
                elif input_mode and event.unicode.isdigit():
                    input_text += event.unicode
        
        # 更新
        demo.update()
        
        # 绘制
        screen.fill(BACKGROUND)
        demo.draw(screen)
        
        # 绘制输入框
        if input_mode:
            pygame.draw.rect(screen, (60, 70, 90), 
                           (WIDTH // 2 - 150, HEIGHT // 2 - 25, 300, 50), 
                           border_radius=5)
            pygame.draw.rect(screen, (100, 120, 150), 
                           (WIDTH // 2 - 150, HEIGHT // 2 - 25, 300, 50), 
                           2, border_radius=5)
            
            prompt = text_font.render("请输入n值 (1-200):", True, TEXT_COLOR)
            screen.blit(prompt, (WIDTH // 2 - 140, HEIGHT // 2 - 50))
            
            input_surface = text_font.render(input_text, True, TEXT_COLOR)
            screen.blit(input_surface, (WIDTH // 2 - 140, HEIGHT // 2 - 10))
        
        pygame.display.flip()
        clock.tick(FPS)
    
    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()